package com.blood.modules.system.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;
import com.blood.common.util.Tools;
import com.blood.core.config.file.FileProperties;
import com.blood.core.resp.BusinessException;
import com.blood.core.resp.GlobalResultStatus;
import com.blood.core.resp.ResponseResult;
import com.blood.modules.system.dto.resp.UploadResp;
import com.blood.modules.system.service.IFTPService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 服务器文件管理
 *
 * @author daoren
 */
@Slf4j
@Service
public class FTPServiceImpl implements IFTPService {

    @Autowired
    private FileProperties fileProperties;
    private static final FastDateFormat NORM_DATE_FORMAT = FastDateFormat.getInstance("yyyy/MM/dd");
    private final static String fileDir = "/";
    FTPClient ftpClient;
    private static List<String> uploadFIlePrefix;

    static {
        uploadFIlePrefix = new ArrayList<>(19);
        uploadFIlePrefix.add(".BMP");
        uploadFIlePrefix.add(".JPEG");
        uploadFIlePrefix.add(".JPG");
        uploadFIlePrefix.add(".MBM");
        uploadFIlePrefix.add(".JP2");
        uploadFIlePrefix.add(".GIF");
        uploadFIlePrefix.add(".TIFF");
        uploadFIlePrefix.add(".EXIF");
        uploadFIlePrefix.add(".WBMP");
        uploadFIlePrefix.add(".PNG");
        uploadFIlePrefix.add(".EPS");
        uploadFIlePrefix.add(".PDF");
        uploadFIlePrefix.add(".PPT");
        uploadFIlePrefix.add(".WORD");
        uploadFIlePrefix.add(".XLS");
        uploadFIlePrefix.add(".XLSX");
        uploadFIlePrefix.add(".RTF");
        uploadFIlePrefix.add(".WORDX");
        uploadFIlePrefix.add(".MP4");
    }

    @Override
    public ResponseResult<UploadResp> upload(MultipartFile file) {
        UploadResp resp = new UploadResp();
        // 上传文件保存在当天日期命名的文件夹下
        Date date = new Date();
        String today = DateUtil.format(date, NORM_DATE_FORMAT);
        File path = new File(fileProperties.getUploadFolder());
        File parent = new File(path, today);
        if (!parent.exists()) {
            parent.mkdirs();
        }

        String originalFilename = file.getOriginalFilename();
        // 获取文件后缀
        String prefix = originalFilename.substring(originalFilename.lastIndexOf("."));
        //防止webshell攻击
        if (!uploadFIlePrefix.contains(prefix.toUpperCase())) {
            throw new BusinessException("上传文件失败!");
        }
        String filename = Tools.getFileName() + prefix;
        File newPath = new File(parent, filename);
        try {
            file.transferTo(newPath);
        } catch (IOException e) {
            log.error("上传文件失败", e);
            throw new BusinessException("上传文件失败!");
        }
        resp.setFilePath(today + "/" + filename);
        resp.setFileSize(file.getSize());
        resp.setOriginalFileName(file.getOriginalFilename());
        return GlobalResultStatus.SUCCESS.toResult().response(resp);
    }

    @Override
    public ResponseResult<List<UploadResp>> batchUpload(List<MultipartFile> files) {
        List<UploadResp> uploadRespList = new ArrayList<>();
        for (MultipartFile file : files) {
            ResponseResult<UploadResp> upload = this.upload(file);
            if (upload.isSuccess()) {
                uploadRespList.add(upload.getBody());
            }
        }
        return GlobalResultStatus.SUCCESS.toResult().response(uploadRespList);
    }

    @Override
    public void downloadFile(String fileName, String localPath) {
        try {
            this.initConnect();
            log.info("进入FTP服务器下载目录");
            if (!ftpClient.changeWorkingDirectory(fileProperties.getUploadFolder())) {
                log.info("目录不存在");
                throw new BusinessException("目录不存在");
            }

            log.info("匹配查找文件");
            FTPFile[] fs = ftpClient.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    log.info("开始下载");
                    File localFile = new File(localPath + "/" + ff.getName());
                    OutputStream is = new FileOutputStream(localFile);
                    ftpClient.retrieveFile(ff.getName(), is);
                    is.close();
                    log.info("下载完成");
                } else {
                    log.info("找不到文件");
                }
            }
            ftpClient.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            log.info("断开FTP连接");
            this.disConnect();
        }
    }


    @Override
    public void batchRemove(List<String> filePath) {
        try {
            this.initConnect();
            // 获取当前Ftp服务器登录目录,主要是解决Linux下Ftp服务器删除附件问题
            String curDirectory = ftpClient.printWorkingDirectory();
            // 若为空,则定位到根目录
            if (StringUtils.isEmpty(curDirectory)) {
                curDirectory = "";
            }
            // 删除文件,转移到FTP服务器目录
            for (String path : filePath) {
                int lastIndexOf = path.lastIndexOf("/");
                String fileRootPath = curDirectory + fileDir + fileProperties.getUploadFolder() + fileDir + path.substring(0, lastIndexOf);
                //跳转到文件根路径
                ftpClient.changeWorkingDirectory(fileRootPath);
                ftpClient.deleteFile(new String(path.substring(lastIndexOf).getBytes("GBK"), "iso-8859-1"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            this.disConnect();
        }
    }


    /**
     * 链接服务器
     *
     * @throws IOException
     */
    private void initConnect() throws IOException {
        ftpClient = new FTPClient();
        int reply;
        log.info("连接FTP服务器");
        ftpClient.connect(fileProperties.getHost(), fileProperties.getPort());

        log.info("登录");
        ftpClient.login(fileProperties.getUsername(), fileProperties.getPassword());

        reply = ftpClient.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            log.info("FTP连接失败");
            ftpClient.disconnect();
            throw new BusinessException("FTP连接失败");
        }
    }

    /**
     * 关闭链接
     *
     * @throws IOException
     */
    private void disConnect() {
        try {
            ftpClient.disconnect();
        } catch (IOException e) {
            log.error("FTP断开失败");
            e.printStackTrace();
        }
    }


}
